package cs348a.data;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SequenceData {

	/** List of sites */
	public ArrayList<Site> siteList = new ArrayList<Site>();
	
//	/** List of tour sites */
//	public ArrayList<Site> tourSiteList = new ArrayList<Site>();
	
	// Stats of site data
	public float minX = Float.MAX_VALUE;
	public float maxX = Float.MIN_VALUE;

	public float minY = Float.MAX_VALUE;
	public float maxY = Float.MIN_VALUE;

	public float minZ = Float.MAX_VALUE;
	public float maxZ = Float.MIN_VALUE;
	
	// TODO: update and show sequence stats
	public float curvature = 0;
	public float length = 0;
	public float height = 0;
	
	private ArrayList<ChangeListener> clList = new ArrayList<ChangeListener>();
	private ChangeEvent ce = new ChangeEvent(this);
	
	/**
	 * Returns the number of sites.
	 * 
	 * @return
	 */
	public int numSites() {
		return siteList.size();
	}
	
	/**
	 * Parses the data file to create data structures
	 * 
	 * @param file
	 */
	public void parseDataFile(File file) {		
		try {
			BufferedReader input =  new BufferedReader(new FileReader(file));
			
			try {
				resetData();
				
				String line = null;
				
				boolean isOn = true;
				
				int idx = 0;
				
				while (( line = input.readLine()) != null){
					Scanner scanner = new Scanner(line);
					scanner.useDelimiter("\t");
					
					if(scanner.hasNext()) {
						float x = new Float(scanner.next());
						float y = new Float(scanner.next());
						float z = new Float(scanner.next());
						int i = new Float(scanner.next()).intValue();
						
						if(i == 1) {
							siteList.add(new Site(x, y, z, idx, isOn));
//							tourSiteList.add(new Site(x, y, z, idx, isOn));
							
							idx++;
						} else {
							siteList.add(new Site(x, y, z, -1, isOn));
						}
						
						// get stats
						if(x < minX) minX = x;
						if(x > maxX) maxX = x;
						if(y < minY) minY = y;
						if(y > maxY) maxY = y;
						if(z < minZ) minZ = z;
						if(z > maxZ) maxZ = z;
						
						isOn = !isOn; // toggle on/off
					}
				}
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			finally {
				input.close();
				fireChanged();
			}
		}
	    catch (IOException e){
	      e.printStackTrace();
	    }
	}
	
	/**
	 * Replaces the list with new site values
	 * 
	 * @param delIdx
	 * @param siteNo
	 * @param newList
	 */
	public void replaceSites(int delIdx, int siteNo ,List<Site> newList){
		// delete obsolete points
		int deletePoint = delIdx + 1;
		for(int i = deletePoint; i <= siteNo; i++) {
			siteList.remove(deletePoint);
		}
		
		// add new points
		// 1. add off point
		Site s1 = siteList.get(delIdx);
		Site s2 = newList.get(0);
		
		Site ns = new Site(
				(s1.x+s2.x)/2, 
				(s1.y+s2.y)/2,
				(s1.z+s2.z)/2,
				-1, false);

		siteList.add(deletePoint, ns);
		
		// 2. add points except last point
		siteList.addAll(deletePoint+1, newList);
		
		fireChanged();
	}

	/**
	 * Resets the data
	 */
	private void resetData() {
		siteList.clear();
		
		minX = Integer.MAX_VALUE;
		maxX = Integer.MIN_VALUE;

		minY = Integer.MAX_VALUE;
		maxY = Integer.MIN_VALUE;

		minZ = Integer.MAX_VALUE;
		maxZ = Integer.MIN_VALUE;
	}
	
	/**
	 * Adds change listener
	 * 
	 * @param cl
	 */
	public void addChangeListener(ChangeListener cl) {
		clList.add(cl);
	}
	
	/**
	 * Removes change listener
	 * 
	 * @param cl
	 */
	public void removeChangeListener(ChangeListener cl) {
		clList.remove(cl);
	}
	
	/**
	 * Fire change event
	 */
	private void fireChanged() {
		for(ChangeListener cl : clList) {
			cl.stateChanged(ce);
		}
	}
}
